package stu.officedrunker.applications.common;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.context.MessageSourceResolvable;
import org.springframework.core.Conventions;
import org.springframework.util.Assert;

import stu.officedrunker.applications.common.exception.CommonException;
import stu.officedrunker.applications.common.model.BaseObject;

/**
 * 와글 결과 메시지 처리 클래스
 * 
 * @author 서성수
 */
@SuppressWarnings("serial")
public class CommonResultMessage extends BaseObject implements MessageSourceResolvable {

	/**
	 * 결과 코드
	 */
	private final CommonResultCode resultCode;

	/**
	 * 메시지 코드 리스트
	 */
	private String[] codes;

	/**
	 * 메시지 인수 리스트
	 */
	private Object[] arguments;

	/**
	 * 기본 메시지
	 */
	private String defaultMessage;

	/**
	 * 모델 맵
	 */
	private Map<String, Object> model;

	/**
	 * 생성자
	 * 
	 * @param resultCode
	 *            {@link CommonResultCode}
	 */
	public CommonResultMessage(CommonResultCode resultCode) {
		Assert.notNull(resultCode, "ResultCode must not be null");
		this.resultCode = resultCode;
		this.codes = new String[] { resultCode.messageCode() };
		this.defaultMessage = resultCode.name();
		this.model = new HashMap<String, Object>();
	}

	/**
	 * 결과 코드
	 */
	public CommonResultCode getResultCode() {
		return resultCode;
	}

	/**
	 * 메시지 코드 리스트 설정
	 */
	public CommonResultMessage setCodes(String... codes) {
		Assert.notEmpty(codes, "Codes must not be empty");
		this.codes = codes;
		return this;
	}

	/**
	 * 메시지 인수 설정
	 */
	public CommonResultMessage setArguments(Object... arguments) {
		this.arguments = arguments;
		return this;
	}

	/**
	 * 기본 메시지 설정
	 */
	public CommonResultMessage setDefaultMessage(String defaultMessage) {
		this.defaultMessage = defaultMessage;
		return this;
	}

	/**
	 * 메시지 소스 설정
	 * 
	 * @param msr
	 *            {@link MessageSourceResolvable}
	 * @return this
	 */
	public CommonResultMessage setMessage(MessageSourceResolvable msr) {
		Assert.notNull(msr, "MessageSourceResolvable must not be null");
		this.codes = msr.getCodes();
		this.arguments = msr.getArguments();
		this.defaultMessage = msr.getDefaultMessage();
		return this;
	}

	/**
	 * 모델 객체
	 */
	public Map<String, Object> getModel() {
		return this.model;
	}

	/**
	 * 모델 어트리뷰트 값을 추가한다.
	 * 
	 * @param attributeName
	 *            어트리뷰트 이름
	 * @param attributeValue
	 *            어트리뷰트 값
	 * @return this
	 */
	public CommonResultMessage addObject(String attributeName, Object attributeValue) {
		this.model.put(attributeName, attributeValue);
		return this;
	}

	/**
	 * 모델 어트리뷰트 값을 추가한다.
	 * 
	 * @param attributeValue
	 *            어트리뷰트 값
	 * @return this
	 */
	public CommonResultMessage addObject(Object attributeValue) {
		Assert.notNull(attributeValue, "Model object must not be null");
		if (!(attributeValue instanceof Collection) || !((Collection<?>) attributeValue).isEmpty()) {
			this.model.put(Conventions.getVariableName(attributeValue), attributeValue);
		}
		return this;
	}

	/**
	 * 모델 어트리뷰트 맵을 추가한다.
	 * 
	 * @param model
	 *            모델 어트리뷰트 맵
	 * @return this
	 */
	public CommonResultMessage addAllObjects(Map<String, Object> model) {
		this.model.putAll(model);
		return this;
	}

	/**
	 * Raise {@link CommonException}
	 * 
	 * @throws CommonException
	 */
	public void raise() throws CommonException {
		throw new CommonException(this);
	}

	/**
	 * Raise {@link CommonException}
	 * 
	 * @throws CommonException
	 */
	public void raise(Throwable cause) throws CommonException {
		throw new CommonException(this, cause);
	}

	//@Override
	public String[] getCodes() {
		return codes;
	}

	//@Override
	public Object[] getArguments() {
		return arguments;
	}

	//@Override
	public String getDefaultMessage() {
		return defaultMessage;
	}

}